package com.qlogic.commons.platform.impls.lucene.handler;

import java.io.IOException;
import java.io.InputStream;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.pdfbox.cos.COSDocument;
import org.pdfbox.encryption.DocumentEncryption;
import org.pdfbox.exceptions.CryptographyException;
import org.pdfbox.exceptions.InvalidPasswordException;
import org.pdfbox.pdfparser.PDFParser;
import org.pdfbox.pdmodel.PDDocument;
import org.pdfbox.pdmodel.PDDocumentInformation;
import org.pdfbox.util.PDFTextStripper;

public class PDFBoxPDFHandler implements ContentHandler {

	public static String password = "-password";
	
	private COSDocument cosDoc;

	public String getText (InputStream is, String encoding) throws ContentHandlerException {
		return getText (is, true, encoding);
	}
	
	public String getText (InputStream is, boolean closeDoc, String encoding) throws ContentHandlerException {
		cosDoc = null;
		try {
			cosDoc = parseDocument(is);
		} catch (IOException e) {
			closeCOSDocument ();
			throw new ContentHandlerException("Cannot parse PDF document", e);
		}

		// decrypt the PDF document, if it is encrypted
		try {
			if (cosDoc.isEncrypted()) {
				DocumentEncryption decryptor = new DocumentEncryption(cosDoc);
				decryptor.decryptDocument(password);
			}
		} catch (CryptographyException e) {
			closeCOSDocument ();
			throw new ContentHandlerException("Cannot decrypt PDF document", e);
		} catch (InvalidPasswordException e) {
			closeCOSDocument ();
			throw new ContentHandlerException("Cannot decrypt PDF document", e);
		} catch (IOException e) {
			closeCOSDocument ();
			throw new ContentHandlerException("Cannot decrypt PDF document", e);
		}

		// extract PDF document's textual content
		String docText = null;
		try {
			PDFTextStripper stripper = new PDFTextStripper();
			docText = stripper.getText(new PDDocument(cosDoc));
		} catch (IOException e) {
			closeCOSDocument ();
			throw new ContentHandlerException("Cannot parse PDF document", e);
		}
		if (closeDoc) {
			closeCOSDocument ();
		}
		return docText;
	}

	public Document getDocument(InputStream is, String encoding) throws ContentHandlerException {
		String docText = getText (is, false, encoding);
		Document doc = new Document();
		if (docText != null) {
			doc.add(new Field(BODY, docText, Field.Store.NO, Field.Index.TOKENIZED));
		}

		// extract PDF document's meta-data
		PDDocument pdDoc = null;
		try {
			pdDoc = new PDDocument(cosDoc);
			PDDocumentInformation docInfo = pdDoc.getDocumentInformation();
			String author = docInfo.getAuthor();
			String title = docInfo.getTitle();
			String keywords = docInfo.getKeywords();
			String summary = docInfo.getSubject();
			if ((author != null) && (!author.equals(""))) {
				doc.add(new Field(AUTHOR, author, Field.Store.YES, Field.Index.TOKENIZED));
			}
			if ((title != null) && (!title.equals(""))) {
				doc.add(new Field (TITLE, title, Field.Store.YES, Field.Index.TOKENIZED));
			}
			if ((keywords != null) && (!keywords.equals(""))) {
				doc.add(new Field (KEYWORDS, keywords, Field.Store.YES, Field.Index.TOKENIZED));
			}
			if ((summary != null) && (!summary.equals(""))) {
				doc.add(new Field (SUMMARY, summary, Field.Store.YES, Field.Index.TOKENIZED));
			}
		} catch (Exception e) {
			closeCOSDocument();
			closePDDocument(pdDoc);
			System.err.println("Cannot get PDF document meta-data: "
					+ e.getMessage());
		}
		closeCOSDocument();
		closePDDocument(pdDoc);
		return doc;
	}

	private static COSDocument parseDocument(InputStream is) throws IOException {
		PDFParser parser = new PDFParser(is);
		parser.parse();
		return parser.getDocument();
	}

	private void closeCOSDocument () {
		if (cosDoc != null) {
			try {
				cosDoc.close();
			} catch (IOException e) {
				// eat it, what else can we do?
			}
		}
	}

	private void closePDDocument(PDDocument pdDoc) {
		if (pdDoc != null) {
			try {
				pdDoc.close();
			} catch (IOException e) {
				// eat it, what else can we do?
			}
		}
	}

}
